package com.sky.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.annotation.AutoFill;
import com.sky.constant.MessageConstant;
import com.sky.constant.StatusConstant;
import com.sky.context.BaseContext;
import com.sky.dto.CategoryDTO;
import com.sky.dto.CategoryPageQueryDTO;
import com.sky.dto.SetmealDishDTO;
import com.sky.dto.mapper.CategoryDTOMapper;
import com.sky.entity.Category;
import com.sky.entity.Dish;
import com.sky.entity.Setmeal;
import com.sky.entity.SetmealDish;
import com.sky.enumeration.OperationType;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.exception.UpdateStatusErrorException;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealDishMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.result.PageResult;
import com.sky.service.CategoryService;
import com.sky.mapper.CategoryMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author luo20
 * @description 针对表【category(菜品及套餐分类)】的数据库操作Service实现
 * @createDate 2025-07-06 12:49:34
 */
@Service
@Slf4j
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category>
        implements CategoryService {

    @Autowired
    private CategoryDTOMapper categoryDTOMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private DishMapper dishMapper;

    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;


    @Override
    public PageResult<Category> pageCategory(CategoryPageQueryDTO categoryPageQueryDTO) {
        // 开启分页
        PageHelper.startPage(categoryPageQueryDTO.getPage(), categoryPageQueryDTO.getPageSize());
        // 条件构造器
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(ObjectUtils.isNotEmpty(categoryPageQueryDTO.getName()), Category::getName, categoryPageQueryDTO.getName());
        lambdaQueryWrapper.eq(ObjectUtils.isNotEmpty(categoryPageQueryDTO.getType()), Category::getType, categoryPageQueryDTO.getType());
        // 查询数据
        List<Category> categoryList = categoryMapper.selectList(lambdaQueryWrapper);
        // 封装分页结果
        Page<Category> categoryPage = (Page<Category>) categoryList;
        // 返回结果
        return PageResult.<Category>builder()
                .total(categoryPage.getTotal())
                .records(categoryPage.getResult()).build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer saveCategory(CategoryDTO categoryDTO) {
        // 转换对象
        Category category = categoryDTOMapper.toCategory(categoryDTO);
        // 设置创建时间和更新时间
        // category.setCreateTime(LocalDateTime.now());
        // category.setUpdateTime(LocalDateTime.now());
        // 设置创建人ID和修改人ID
        // category.setCreateUser(BaseContext.getCurrentId());
        // category.setUpdateUser(BaseContext.getCurrentId());
        // 默认禁用
        category.setStatus(StatusConstant.DISABLE);
        return categoryMapper.insertCategory(category);
    }

    @Override
    public Integer delCategoryById(Integer id) {
        // 启用中的分类不能删除
        Category category = categoryMapper.selectById(id);
        if (Objects.equals(category.getStatus(), StatusConstant.ENABLE)) {
            // 当前分类为启用状态，不能删除
            throw new DeletionNotAllowedException(MessageConstant.CATEGORY_ON_SALE);
        }
        // 根据id查询是否有对应菜品
        LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishLambdaQueryWrapper.eq(Dish::getCategoryId, id);
        List<Dish> selectedDishList = dishMapper.selectList(dishLambdaQueryWrapper);
        if (CollectionUtils.isNotEmpty(selectedDishList) ) {
            // 获取菜品名称
            List<String> dishNameList = selectedDishList.stream().map(Dish::getName).toList();
            // 当前分类关联了菜品,不能删除
            throw new DeletionNotAllowedException(MessageFormat.format(MessageConstant.CATEGORY_BE_RELATED_BY_DISH, StringUtils.join(dishNameList, ",")));
        }
        // 根据id查询是否有对应套餐
        LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
        setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId, id);
        List<Setmeal> setmealList = setmealMapper.selectList(setmealLambdaQueryWrapper);
        if (CollectionUtils.isNotEmpty(setmealList)) {
            // 获取套餐名称
            List<String> setmealNameList = setmealList.stream().map(Setmeal::getName).toList();
            // 当前分类关联了套餐,不能删除
            throw new DeletionNotAllowedException(MessageFormat.format(MessageConstant.CATEGORY_BE_RELATED_BY_SETMEAL, StringUtils.join(setmealNameList, ",")));
        }
        return categoryMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updStatus(Category category) {
        // 更新分类状态
        Category c = new Category().setId(category.getId())
                .setStatus(category.getStatus());
        Integer result = categoryMapper.updateCategory(c);
        // 如果是禁用操作，处理关联的菜品和套餐
        if (StatusConstant.DISABLE.equals(category.getStatus())) {
            handleRelatedDishesAndSetmeals(category.getId());
        }
        return result;
    }

    public void handleRelatedDishesAndSetmeals(Long categoryId) {
        // 1. 禁用分类下的所有菜品
        disableDishesByCategory(categoryId);

        // 2. 禁用分类下的所有套餐及其关联菜品
        disableSetmealsByCategory(categoryId);
    }

    public void disableDishesByCategory(Long categoryId) {
        // 根据分类id查询需要禁用的菜品列表
        List<Dish> dishList = dishMapper.selectByDishConditions(new Dish()
                .setCategoryId(categoryId)
                .setStatus(StatusConstant.ENABLE)
        );
        // 更新菜品状态
        updateDishStatus(dishList);
    }

    public void disableSetmealsByCategory(Long categoryId) {
        // 根据分类id查询还是起售状态的套餐列表
        List<Setmeal> setmealList = setmealMapper.selectByCategoryConditions(new Setmeal()
                .setCategoryId(categoryId)
                .setStatus(StatusConstant.ENABLE));
        if (!CollectionUtils.isEmpty(setmealList)) {
            // 获取套餐ids
            List<Long> setmealIds = setmealList.stream().map(Setmeal::getId).collect(Collectors.toList());
            // 创建Setmeal存入SetmealList中
            List<Setmeal> updateSetmealList = setmealIds.stream()
                    .map(setmealId -> new Setmeal()
                            .setId(setmealId)
                            .setStatus(StatusConstant.DISABLE)
                    ).collect(Collectors.toList());
            // 禁用套餐
            Integer setmealAffected = setmealMapper.batchUpdateStatus(updateSetmealList);
            if (setmealAffected < setmealList.size()) {
                log.warn("部分套餐状态更新失败，预期更新 {} 条，实际更新 {} 条", setmealList.size(), setmealAffected);
                throw new UpdateStatusErrorException(MessageConstant.UPDATE_SETMEAL_STATUS_FAILED);
            }
        }
    }

    // 判断菜品列表不为空就批量更新
    public void updateDishStatus(List<Dish> dishList) {
        if (!CollectionUtils.isEmpty(dishList)) {
            // 构造 List<Dish>，仅需设置 id 和 status
            List<Dish> updateDishList = dishList.stream()
                    .map(d -> {
                        return new Dish()
                                .setId(d.getId())
                                .setStatus(StatusConstant.DISABLE);
                    }).collect(Collectors.toList());
            // 批量更新菜品状态
            Integer dishAffected = dishMapper.batchUpdateStatus(updateDishList);
            if (dishAffected < dishList.size()) {
                log.warn("部分菜品状态更新失败，预期更新 {} 条，实际更新 {} 条", dishList.size(), dishAffected);
                throw new UpdateStatusErrorException(MessageConstant.UPDATE_DISH_STATUS_FAILED);
            }
        }
    }

    @Override
    @AutoFill(value = OperationType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    public Integer update(CategoryDTO categoryDTO) {
        // 对象转换
        Category category = categoryDTOMapper.toCategory(categoryDTO);
        // 设置更新时间
        // category.setUpdateTime(LocalDateTime.now());
        // 设置更新人
        // category.setUpdateUser(BaseContext.getCurrentId());
        // 创建条件构造器
        LambdaUpdateWrapper<Category> categoryLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        categoryLambdaUpdateWrapper.eq(Category::getId, category.getId());
        // categoryLambdaUpdateWrapper.eq(Category::getType,category.getType());
        categoryLambdaUpdateWrapper.set(Category::getName, category.getName());
        categoryLambdaUpdateWrapper.set(Category::getSort, category.getSort());
        categoryLambdaUpdateWrapper.set(Category::getUpdateTime, category.getUpdateTime());
        categoryLambdaUpdateWrapper.set(Category::getUpdateUser, category.getUpdateUser());

        return categoryMapper.update(categoryLambdaUpdateWrapper);
    }

    @Override
    @Cacheable(value = "sky-take-out:category:list",key = "#type != null ? #type:'allCategory'")
    public List<Category> list(Integer type) {
        return categoryMapper.selectByType(type);// 返回 [] 或数据列表
    }

    @Override
    public List<Dish> selectByCategoryIdAndName(Long categoryId, String name) {
        Dish dish = new Dish()
                .setCategoryId(categoryId)
                .setName(name);
        return dishMapper.selectByDishConditions(dish);
    }
}




